home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.03 Mar 90 / Mouse Source / MouseDemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-23  |  19.1 KB  |  804 lines  |  [TEXT/KAHL]

  1. /*                                                MouseDemo.c                                        */
  2. /*
  3.  * Mouse selection mainline.
  4.  *
  5.  * Copyright © 1989 Martin Minow. All rights reserved.
  6.  *
  7.  * You may incorporate portions of this program in your
  8.  * applications without restriction as long as this
  9.  * copyright notice remains intact and the applications
  10.  * are not sold for profit and this source is not
  11.  * redistributed for profit.
  12.  */
  13. #include "TrackEdit.h"
  14. /*
  15.  * Set DEBUG 1 to make a very small window so you can
  16.  * use the Think C debugger without getting unwanted
  17.  * window update events.
  18.  */
  19. #define DEBUG                     0
  20. #define    NIL                            (0L)
  21. #define TOP_MARGIN            4
  22. #define SIDE_MARGIN            4
  23. #define sBarWidth                15        /* Scroll bar width                */
  24. #define    THE_FONT                "\pHelvetica"
  25. #define    FONT_SIZE                18
  26. /*
  27.  * We always store the current TrackHandle in a local
  28.  * variable named track_handle.
  29.  */
  30. #define TR                            (**track_handle)
  31. /*
  32.  * height and width define the extants of a rectangle.
  33.  */
  34. #define height(r)                ((r).bottom - (r).top)
  35. #define    width(r)                ((r).right - (r).left)
  36.  
  37. /*
  38.  * Menu organization
  39.  */
  40. enum Menus {
  41.     MENU_Apple            = 1,
  42.     MENU_File                = 256,
  43.     MENU_Edit                = 257,
  44.     MENU_Ctrl                = 258
  45. };
  46.  
  47. enum Apple_Menu {
  48.     Apple_About = 1
  49. };
  50.  
  51. enum File_Menu {
  52.     File_Debug = 1,
  53.     Unused1,
  54.     File_Reinitialize,
  55.     Unused2,
  56.   File_Quit
  57. };
  58.  
  59. enum Edit_Menu {
  60.     Edit_Undo = 1,
  61.     Edit_Skip,
  62.     Edit_Cut,
  63.     Edit_Copy,
  64.     Edit_Paste,
  65.     Edit_Clear
  66. };
  67.  
  68. enum Control_Menu {
  69.     Ctrl_Script = 1,
  70.     Ctrl_Smart,
  71.     Ctrl_Unused1,
  72.     Ctrl_Hilite,
  73.     Ctrl_Caret,
  74.     Ctrl_ObeyCR,
  75.     Ctrl_AutoScroll,
  76.     Ctrl_Unused2,
  77.     Ctrl_JustLeft,        /* Keep in            */
  78.     Ctrl_JustCenter,    /*  this                */
  79.     Ctrl_JustRight        /*   order.            */
  80. };
  81.  
  82. #define keyCodeShift    8 
  83. enum Arrow_Keys {
  84.     /*
  85.      * ADB keyboard arrow keys and keypad keys
  86.      */
  87.     Left_Arrow    = (0x7B << keyCodeShift),
  88.     Right_Arrow    = (0x7C << keyCodeShift),
  89.     Down_Arrow    = (0x7D << keyCodeShift),
  90.     Up_Arrow        = (0x7E << keyCodeShift),
  91.     Home_Key        = (0x73 << keyCodeShift),
  92.     End_Key            = (0x77 << keyCodeShift),
  93.     Pg_Down_Key    = (0x74 << keyCodeShift),
  94.     Pg_Up_Key        = (0x79 << keyCodeShift),
  95.     Help_Key        = (0x72 << keyCodeShift),
  96.     /*
  97.      * Mac-Plus arrow keys.
  98.      */
  99.     Right_Plus    = (0x42 << keyCodeShift),
  100.     Left_Plus        = (0x46 << keyCodeShift),
  101.     Down_Plus        = (0x48 << keyCodeShift),
  102.     Up_Plus            = (0x4D << keyCodeShift)
  103. };
  104.  
  105. /*
  106.  * This is the data shown in the display.
  107.  */
  108. char                fubar[] =
  109. "The term FUBAR actually first appeared during the reign"
  110. " of Queen Anne of England (1702-1714), the last ruling"
  111. " sovereign of the Stuart Dynasty (1603-1714). The Duke"
  112. " of Marlborough (1650-1722), John Churchill, Sir"
  113. " Winston’s great great… grandfather, after his great"
  114. " victory at the battle of Blenhiem (August 13, 1704)"
  115. " against the French, in Austria, had some captured"
  116. " French dispatches translated.  The translator,"
  117. " unfortunately unknown, but believed to be a Lance"
  118. " Corporal in the Royal Guards, having some difficulty"
  119. " translating a slang French expression used by Marshall"
  120. " Tallard, the defeated French general, gave up in"
  121. " despair and wrote in FUBAR; which, although not"
  122. " literally translating the dispatch, expressed the"
  123. " French general’s analysis of the situation.\r"
  124. "Smith-Huxley, J.P., “The Augustan Age of Good Queen"
  125. " Anne,” pp 386-387, R. Clay Ltd, London, (1903)"
  126. " SBN 384-82210-2.";
  127.  
  128. #define FUBAR_SIZE    (sizeof fubar - 1)    /* No NUL trail    */
  129.  
  130. WindowPtr        the_window;
  131. TrackHandle    the_track_handle;
  132. MenuHandle    apple_menu;
  133. MenuHandle    file_menu;
  134. MenuHandle    edit_menu;
  135. MenuHandle    ctrl_menu;
  136.  
  137. /*
  138.  * Justification flags.  Keep in this order.
  139.  */
  140. INTEGER    justify[] = {
  141.     trackJustLeft, trackJustCenter, trackJustRight
  142. };
  143. Boolean            do_autoscroll;
  144.  
  145. /*
  146.  * These variables manage transfers to/from the desk
  147.  * scrap.  See Chernicoff, Macintosh Revealed, Vol 2.
  148.  */
  149. Boolean            scrap_changed;            /* TRUE after Cut/Copy    */
  150. INTEGER            scrap_count;                /* ZeroScrap counter        */
  151. /*
  152.  * Prototypes
  153.  */
  154. void                do_command(long);
  155. void                do_mouse(EventRecord);
  156. void                enable_edit_menu(TrackHandle, Boolean);
  157. void                get_desk_scrap(void);
  158. void                keyin(TrackHandle, EventRecord);
  159. void                main(void);
  160. pascal void    my_caret(Rect *, TrackPtr);
  161. pascal void    my_hilite(Rect *, TrackPtr);
  162. void                put_desk_scrap(void);
  163. void                setup(void);
  164. void                get_text_box(Rect *, WindowPtr);
  165.  
  166. /*
  167.  * main()
  168.  * Mainline: initialize the application, then process
  169.  * mouse and menu events.
  170.  */
  171. void
  172. main()
  173. {
  174.         Boolean                    is_event;
  175.         WindowPtr                window;
  176.         EventRecord            event;
  177.         GrafPtr                    save_port;
  178.         TrackHandle            track_handle;
  179.         Rect                        box;
  180.  
  181.         setup();
  182.         for (;;) {
  183.             SystemTask();
  184.             TrackIdle(the_track_handle);
  185.             is_event = GetNextEvent(everyEvent, &event);
  186.             if (is_event) {
  187.                 if (event.what == activateEvt
  188.                  || event.what == updateEvt)
  189.                      window = (WindowPtr) event.message;
  190.                 else {
  191.                     window = FrontWindow();
  192.                 }
  193.                 if (window != the_window)
  194.                     track_handle = NIL;
  195.                 else {
  196.                     track_handle = (TrackHandle) GetWRefCon(window);
  197.                     if (track_handle != NIL
  198.                      && track_handle != the_track_handle)
  199.                          DebugStr("\pBogus track_handle");
  200.                 }
  201.                 switch (event.what) {
  202.                 case mouseDown:
  203.                     do_mouse(event);
  204.                     break;
  205.                 case keyDown:
  206.                 case autoKey:
  207.                     keyin(track_handle, event);
  208.                     break;
  209.                 case activateEvt:
  210.                     /*
  211.                      * Activate or deactivate the Track record
  212.                      * as needed.  Also, if we are going to/from
  213.                      * a desk accessory (or another application),
  214.                      * copy the desk scrap and enable/disable
  215.                      * appropriate edit menu options.
  216.                      */
  217.                     if (track_handle != NIL
  218.                      && window == the_window) {
  219.                         if ((event.modifiers & activeFlag) != 0) {
  220.                             TrackActivate(track_handle);
  221.                             get_desk_scrap();
  222.                             enable_edit_menu(track_handle, FALSE);
  223.                         }
  224.                         else /* deactivating */ {
  225.                             TrackDeactivate(track_handle);
  226.                             put_desk_scrap();
  227.                             enable_edit_menu(track_handle, TRUE);
  228.                         }
  229.                     }
  230.                     DrawGrowIcon(window);
  231.                     break;
  232.                 case updateEvt:
  233.                     if (window == the_window
  234.                      && track_handle != NIL) {
  235.                         GetPort(&save_port);
  236.                         SetPort(window);
  237.                         BeginUpdate(window);
  238.                         EraseRect(&window->portRect);
  239.                         /*
  240.                          * Use a local copy of the viewRect in case
  241.                          * the (unlocked) TrackRecord moves.
  242.                          */
  243.                         box = TR.viewRect;
  244.                         TrackUpdate(&box, track_handle);
  245. #if TOP_MARGIN != 0 && SIDE_MARGIN != 0
  246.                         InsetRect(&box, -1, -1);
  247.                         FrameRect(&box);
  248. #endif
  249.                         /*
  250.                          * Must follow TrackUpdate
  251.                          */
  252.                         DrawGrowIcon(window);
  253.                         EndUpdate(window);
  254.                         SetPort(save_port);
  255.                     }
  256.                     break;
  257.                 default:
  258.                     break;
  259.                 }
  260.             }
  261.         }
  262. }
  263.  
  264. /*
  265.  * Handle keystrokes.  Most of this is needed for
  266.  * arrow-key scrolling.
  267.  */
  268. static void
  269. keyin(track_handle, event)
  270. TrackHandle    track_handle;
  271. EventRecord    event;
  272. {
  273.         INTEGER        c;
  274.         LONGINT        choice;
  275.         LONGINT        hdelta, hscroll, hmax;
  276.         LONGINT        vdelta, vscroll, vmax;
  277.  
  278.         /*
  279.          * The arrow keys scroll the window.
  280.          * <Option><Arrow> scrolls single pixels.
  281.          *
  282.          * [h,v]max            The largest amount we will
  283.          *                            scroll the rectangle.
  284.          * [h,v]delta        The amount the arrow key scrolls.
  285.          * [h,v]scroll    The amount we actually scroll.
  286.          */
  287.         hmax = TR.lineWidth - width(TR.viewRect);
  288.         vmax = (TR.nLines * TR.lineHeight)
  289.                  + TR.fontDescent
  290.                  - height(TR.viewRect);
  291.         hdelta = vdelta = TR.lineHeight;
  292.         if ((event.modifiers & optionKey) != 0)
  293.             hdelta = vdelta = 1;
  294.         hscroll = vscroll = 0;
  295.         switch (event.message & keyCodeMask) {
  296.         case Left_Arrow:    case Left_Plus:
  297.             hscroll = -hdelta;                                goto do_scroll;
  298.         case Right_Arrow:    case Right_Plus:
  299.             hscroll = hdelta;                                    goto do_scroll;
  300.         case Up_Arrow:        case Up_Plus:
  301.             vscroll = -vdelta;                                goto do_scroll;
  302.         case Down_Arrow:    case Down_Plus:
  303.             vscroll = vdelta;                                    goto do_scroll;
  304.         case Pg_Up_Key:                        /* Up one screen                    */
  305.             vscroll = (-height(TR.viewRect));    goto do_scroll;
  306.         case Pg_Down_Key:                    /* Down one screen                */
  307.             vscroll = height(TR.viewRect);        goto do_scroll;
  308.         case Home_Key:                    /* Scroll to start of text    */
  309.             hscroll = -TR.leftPixel;
  310.             vscroll = -TR.topPixel;                        goto do_scroll;
  311.         case End_Key:                        /* Scroll to end of text        */
  312.             hscroll = -TR.leftPixel + hmax;
  313.             vscroll = -TR.topPixel + vmax;
  314.             /*
  315.              * Pin the scroll amount against the
  316.              * boundaries of the document and scroll
  317.              * if anything changes.  Note that we can't
  318.              * determine the maximum width of the document
  319.              * if lines are only delimited by <return>.
  320.              */
  321. do_scroll:
  322.             if (hscroll != 0 || vscroll != 0)
  323.                 TrackPinScroll(hscroll, vscroll, track_handle);
  324.             break;
  325.         case Help_Key:
  326.             TrackSelView(track_handle);
  327.             break;
  328.         default:
  329.             c = event.message & charCodeMask;
  330.             if ((event.modifiers & cmdKey) != 0) {
  331.                 if (event.what == keyDown) {
  332.                     choice = MenuKey(c);
  333.                     if (HiWord(choice) != 0)
  334.                         do_command(choice);
  335.                     else {
  336.                         SysBeep(10);        /* Bogus <cmd>    */
  337.                     }
  338.                 }
  339.             }
  340.             else if (track_handle != NIL)
  341.                 TrackKey(c, track_handle);
  342.         }
  343. }
  344. /*
  345.  * do_mouse(event)
  346.  * Process a mouse button press, calling handlers as
  347.  * needed.
  348.  */
  349. static void
  350. do_mouse(event)
  351. EventRecord        event;
  352. {
  353.         WindowPtr            window;
  354.         register int    which_part;
  355.         Rect                    box;
  356.         int                        kind;
  357.         TrackHandle        track_handle;
  358.         long                    new;
  359.         
  360.         which_part = FindWindow(event.where, &window);
  361.         switch (which_part) {
  362.         case inDesk:
  363.             SysBeep(2);
  364.             break;
  365.         case inMenuBar:
  366.             do_command(MenuSelect(event.where));
  367.             break;
  368.         case inSysWindow:
  369.             SystemClick(&event, window);
  370.             break;
  371.         case inGoAway:
  372.             if (window == the_window
  373.              && TrackGoAway(window, event.where))
  374.                     ExitToShell();
  375.             else {
  376.                 kind = ((WindowPeek) window)->windowKind;
  377.                 if (kind < 0)                        /* Desk accessory?            */
  378.                     CloseDeskAcc(kind);
  379.             }
  380.             break;
  381.         case inDrag:
  382.             box = screenBits.bounds;
  383.             box.top += GetMBarHeight();
  384.             InsetRect(&box, 2, 4);
  385.             DragWindow(window, event.where, &box);
  386.             break;
  387.         case inGrow:
  388.             box = screenBits.bounds;
  389.             box.left = 64 + sBarWidth;
  390.             box.top = 64 + sBarWidth;
  391.             box.bottom -= GetMBarHeight();
  392.             new = GrowWindow(window, event.where, &box);
  393.             if (new != 0) {
  394.                 track_handle = (TrackHandle) GetWRefCon(window);
  395.                 EraseRect(&window->portRect);
  396.                 SizeWindow(window, LoWord(new), HiWord(new), TRUE);
  397.                 InvalRect(&window->portRect);
  398.                 get_text_box(&TR.viewRect, window);
  399.             }
  400.             break;
  401.         case inContent:
  402.             if (FrontWindow() != window)
  403.                 SelectWindow(window);
  404.             else {
  405.                 SetPort(window);
  406.                 track_handle = (TrackHandle) GetWRefCon(window);
  407.                 GlobalToLocal(&event.where);
  408.                 TrackClick(
  409.                     event.where,
  410.                     (event.modifiers & shiftKey) != 0,
  411.                     track_handle
  412.                 );                
  413.                 enable_edit_menu(track_handle, FALSE);
  414.             }
  415.             break;
  416.         }
  417. }
  418.  
  419. /*
  420.  * Private hilite function (see Inside Mac I-379).
  421.  * Hilite the selection by underlining it.
  422.  */
  423. pascal void
  424. my_hilite(boxp, tr)
  425. Rect            *boxp;
  426. TrackPtr    tr;
  427. {
  428.         Rect            box;
  429.         
  430.         box = *boxp;
  431.         box.top = box.bottom;
  432.         --box.top;
  433.         InvertRect(&box);
  434. }
  435.  
  436. /*
  437.  * Private caret function (see Inside Mac I-379).
  438.  * Draw the selection as a nice TextEdit vertical line.
  439.  */
  440. pascal void
  441. my_caret(boxp, tr)
  442. Rect            *boxp;
  443. TrackPtr    tr;
  444. {
  445.         InvertRect(boxp);
  446. }
  447.         
  448. /*
  449.  * do_command(which_item)
  450.  * Process menu bar commands.
  451.  */
  452. void
  453. do_command(choice)
  454. long                choice;
  455. {
  456.         int                        item;
  457.         register int    i;
  458.         Str255                name;
  459.         GrafPtr                save_port;
  460.         int                        old_option;
  461.         int                        the_class;
  462.         TrackHandle        track_handle;
  463.         WindowPtr            window;
  464.         
  465.         window = FrontWindow();
  466.         track_handle = (TrackHandle) GetWRefCon(window);
  467.         if (track_handle != the_track_handle)
  468.             DebugStr("\pStrange front window");
  469.         item = LoWord(choice);
  470.         switch (HiWord(choice)) {
  471.         case MENU_Apple:
  472.             GetItem(apple_menu, item, &name);
  473.             if (item == Apple_About)
  474.                 SysBeep(10);                /* No Mouse About                        */
  475.             else {
  476.                 /*
  477.                  * Launch a desk accessory: enable the entire Edit
  478.                  * menu, save the port, call the accessory, then
  479.                  * restore our state.
  480.                  */
  481.                 enable_edit_menu(track_handle, TRUE);
  482.                 GetPort(&save_port);
  483.                 OpenDeskAcc(name);
  484.                 SetPort(save_port);
  485.                 enable_edit_menu(track_handle, FALSE);
  486.             }
  487.             break;
  488.         case MENU_File:
  489.             switch (item) {
  490.             case File_Debug:
  491.                 Debugger();
  492.                 break;
  493.             case File_Reinitialize:
  494.                 TrackSetText(fubar, FUBAR_SIZE, track_handle);
  495.                 break;
  496.             case File_Quit:
  497.                 ExitToShell();
  498.             }
  499.             break;
  500.         case MENU_Edit:
  501.             if (!SystemEdit(item - 1)) {
  502.                 switch (item) {
  503.                 case Edit_Undo:
  504.                     break;
  505.                 case Edit_Cut:
  506.                     TrackCut(track_handle);
  507.                     scrap_changed = TRUE;
  508.                     break;
  509.                 case Edit_Copy:
  510.                     TrackCopy(track_handle);
  511.                     scrap_changed = TRUE;
  512.                     break;
  513.                 case Edit_Paste:
  514.                     TrackPaste(track_handle);
  515.                     break;
  516.                 case Edit_Clear:
  517.                     TrackDelete(track_handle);
  518.                     break;
  519.                 }
  520.             }
  521.             enable_edit_menu(track_handle, FALSE);
  522.             break;
  523.         case MENU_Ctrl:
  524.             switch (item) {
  525.             case Ctrl_Script:
  526.                 _Track_flip(
  527.                     *track_handle, _Track_use_script_manager);
  528.                 CheckItem(
  529.                     ctrl_menu,
  530.                     Ctrl_Script,
  531.                     _Track_is_set(
  532.                         *track_handle, _Track_use_script_manager)
  533.                 );
  534.                 break;
  535.             case Ctrl_Smart:
  536.                 _Track_flip(
  537.                     *track_handle, _Track_use_smart_cut_paste);
  538.                  CheckItem(
  539.                     ctrl_menu,
  540.                     Ctrl_Smart,
  541.                     _Track_is_set(
  542.                         *track_handle, _Track_use_smart_cut_paste)
  543.                 );
  544.                 break;
  545.             case Ctrl_Hilite:
  546.                 TrackDeactivate(track_handle);
  547.                 if (TR.highHook == NIL)
  548.                     TR.highHook = (ProcPtr) my_hilite;
  549.                 else {
  550.                     TR.highHook = NIL;
  551.                 }
  552.                 TrackActivate(track_handle);
  553.                 CheckItem(
  554.                     ctrl_menu, Ctrl_Hilite, (TR.highHook != NIL));
  555.                 break;
  556.             case Ctrl_Caret:
  557.                 TrackDeactivate(track_handle);
  558.                 if (TR.caretHook == NIL)
  559.                     TR.caretHook = (ProcPtr) my_caret;
  560.                 else {
  561.                     TR.caretHook = NIL;
  562.                 }
  563.                 TrackActivate(track_handle);
  564.                 CheckItem(
  565.                     ctrl_menu, Ctrl_Caret, (TR.caretHook != NIL));
  566.                 break;
  567.             case Ctrl_ObeyCR:
  568.                 TR.crOnly = (TR.crOnly == 0) ? -1 : 0;
  569.                 TrackCalText(track_handle);
  570.                 CheckItem(
  571.                     ctrl_menu, Ctrl_ObeyCR, (TR.crOnly < 0));
  572.                 break;
  573.             case Ctrl_AutoScroll:
  574.                 do_autoscroll = !do_autoscroll;
  575.                 TrackAutoView(do_autoscroll, track_handle);
  576.                 CheckItem(
  577.                     ctrl_menu, Ctrl_AutoScroll, do_autoscroll);
  578.                 break;
  579.             case Ctrl_JustLeft:
  580.             case Ctrl_JustCenter:
  581.             case Ctrl_JustRight:
  582.                 TrackSetJust(
  583.                     justify[item - Ctrl_JustLeft], track_handle);
  584.                 for (i = Ctrl_JustLeft; i <= Ctrl_JustRight; i++)
  585.                     CheckItem(ctrl_menu, i, (item == i));
  586.             }
  587.             break;
  588.         }        
  589.         HiliteMenu(0);
  590. }
  591.  
  592. /*
  593.  * enable_edit_menu(track_handle, is_desk_accessory)
  594.  * Enable/disable edit menu items.  All are enabled if
  595.  * we're starting a desk accessory. If not, Enable the
  596.  * Cut, Copy, and Clear options if there's a selection,
  597.  * and Paste if there's something in the track scrap.
  598.  * Note that we don't support Undo.
  599.  */
  600. void
  601. enable_edit_menu(track_handle, starting_desk)
  602. TrackHandle        track_handle;
  603. Boolean                starting_desk;
  604. {    
  605.         if (starting_desk) {
  606.             EnableItem(edit_menu, Edit_Undo);
  607.             EnableItem(edit_menu, Edit_Cut);
  608.             EnableItem(edit_menu, Edit_Copy);
  609.             EnableItem(edit_menu, Edit_Paste);
  610.             EnableItem(edit_menu, Edit_Clear);
  611.         }
  612.         else {
  613.             DisableItem(edit_menu, Edit_Undo);
  614.             if (TrackGetSelectionLength(track_handle) > 0) {
  615.                 EnableItem(edit_menu, Edit_Cut);
  616.                 EnableItem(edit_menu, Edit_Copy);
  617.                 EnableItem(edit_menu, Edit_Clear);
  618.             }
  619.             else {
  620.                 DisableItem(edit_menu, Edit_Cut);
  621.                 DisableItem(edit_menu, Edit_Copy);
  622.                 DisableItem(edit_menu, Edit_Clear);
  623.             }
  624.             if (TrackGetScrapLen() != 0)
  625.                 EnableItem(edit_menu, Edit_Paste);
  626.             else {
  627.                 DisableItem(edit_menu, Edit_Paste);
  628.             }
  629.         }
  630. }
  631.  
  632. /*
  633.  * get_desk_scrap()
  634.  * If there is a TEXT item in the desk scrap, read it in
  635.  * and load it into the Track scrap. The algorithm is
  636.  * adapted from Chernicoff, Macintosh Revealed, vol. 2.
  637.  */
  638. void
  639. get_desk_scrap()
  640. {
  641.         long                offset;
  642.         long                length;        /* Scrap non-empty?            */
  643.  
  644.         /*
  645.          * If the desk scrap contents have changed or
  646.          * the scrap hasn't been initialized, read it
  647.          * and load the Track private scrap.
  648.          */
  649.         if (scrap_count != InfoScrap()->scrapCount
  650.          || InfoScrap()->scrapState < 0) {
  651.             /*
  652.              * The scrap has changed, check for a text item.
  653.              */ 
  654.             length = GetScrap(NIL, 'TEXT', &offset);
  655.             if (length < 0 || TrackFromScrap() != noErr)
  656.                     length = -1;                        /* signal error                */
  657.             if (length > 0)                            /* non-empty scrap?        */
  658.                 EnableItem(edit_menu, Edit_Paste);
  659.             else {
  660.                 TrackSetScrapLen(0);            /* Make it empty            */
  661.                 DisableItem(edit_menu, Edit_Paste);
  662.             }
  663.         }
  664.         scrap_count = InfoScrap()->scrapCount;
  665. }
  666.  
  667. /*
  668.  * put_desk_scrap()
  669.  * Copy the Track scrap to the desk scrap.  Algorithm
  670.  * adapted from Chernicoff, Macintosh Revealed, Vol 2.
  671.  */
  672. void
  673. put_desk_scrap()
  674. {
  675.         OSErr                    status;
  676.         
  677.         if (scrap_changed) {
  678.             scrap_count = ZeroScrap();
  679.             status = TrackToScrap();
  680.             if (status != noErr)
  681.                 DebugStr("\pCan't write scrap.");
  682.             scrap_changed = FALSE;
  683.         }
  684. }
  685.  
  686. /*
  687.  * setup()
  688.  * One-time initialization.
  689.  */
  690. static void
  691. setup()
  692. {
  693.         int                            font_number;
  694.         TrackHandle            track_handle;
  695.         Rect                        box;
  696.  
  697.         /*
  698.          * Normal Macintosh initialization.
  699.          */
  700.         InitGraf(&thePort);
  701.         InitFonts();
  702.         FlushEvents(everyEvent, 0);
  703.         InitWindows();
  704.         InitMenus();
  705.         TEInit();
  706.         InitDialogs(NIL);
  707.         InitCursor();
  708.         MaxApplZone();
  709.         /*
  710.          * Initialize mouse track library.
  711.          */
  712.         TrackInit();
  713.         /*
  714.          * Create the menus and check off the
  715.          * TrackHandle flags.
  716.          */
  717.         apple_menu = NewMenu(MENU_Apple, "\p\024");
  718.         file_menu = NewMenu(MENU_File, "\pFile");
  719.         edit_menu = NewMenu(MENU_Edit, "\pEdit");
  720.         ctrl_menu = NewMenu(MENU_Ctrl, "\pOptions");
  721.         AppendMenu(apple_menu, "\p(No Mouse About;(-");
  722.         AddResMenu(apple_menu, 'DRVR');
  723.         AppendMenu(
  724.             file_menu,
  725.             "\pDebug/.;(-;Reinitialize;(-;Quit/Q"
  726.         );
  727.         AppendMenu(
  728.             edit_menu,
  729.             "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear"
  730.         );
  731.         AppendMenu(
  732.             ctrl_menu,
  733.             "\pScriptManager;Intelligence;(-;"
  734.             "My Hilite;My Caret;No word wrap;Auto-scroll;(-;"
  735.             "Left Justify;Center Justify;Right Justify"
  736.         );
  737.         InsertMenu(apple_menu, 0);
  738.         InsertMenu(file_menu, 0);
  739.         InsertMenu(edit_menu, 0);
  740.         InsertMenu(ctrl_menu, 0);
  741.         DrawMenuBar();
  742.         /*
  743.          * Create the display window, set the proper font,
  744.          * and set the TrackHandle in the window's refCon.
  745.          */
  746.         box = screenBits.bounds;
  747.         box.top += GetMBarHeight() * 2;
  748. #if DEBUG
  749.         box.bottom = 160;
  750.         box.left += 20;
  751.         box.right -= 20;
  752. #endif
  753.         the_window = NewWindow(
  754.                     NIL,                                    /* Allocate storage            */
  755.                     &box,                                    /* Display Rect                    */
  756.                     "\pMouse Demo",                /* Title                                */
  757.                     TRUE,                                    /* Visible on creation    */
  758.                     documentProc,                    /* Window type                    */
  759.                     -1L,                                    /* Show in front                */
  760.                     FALSE,                                /* no GoAway box                */
  761.                     NIL                                        /* RefCon                                */
  762.                 );
  763.         SetPort(the_window);
  764.         GetFNum(THE_FONT, &font_number);
  765.         TextFont(font_number);
  766.         TextSize(FONT_SIZE);
  767.         get_text_box(&box, the_window);
  768.         track_handle = TrackNew(box.right - box.left, &box);
  769.         the_track_handle = track_handle;
  770.         SetWRefCon(the_window, (LONGINT) track_handle);
  771.         TrackSetText(fubar, FUBAR_SIZE, track_handle);
  772.         CheckItem(
  773.             ctrl_menu,
  774.             Ctrl_Script,
  775.             _Track_is_set(
  776.                 *track_handle, _Track_use_script_manager)
  777.         );
  778.         CheckItem(
  779.             ctrl_menu,
  780.             Ctrl_Smart,
  781.             _Track_is_set(
  782.                 *track_handle, _Track_use_smart_cut_paste)
  783.         );
  784.         CheckItem(ctrl_menu, Ctrl_JustLeft, TRUE);
  785.         CheckItem(ctrl_menu, Ctrl_AutoScroll, TRUE);
  786.         do_autoscroll = TRUE;
  787.         TrackAutoView(do_autoscroll, track_handle);
  788. }
  789.  
  790. /*
  791.  * get_text_box()
  792.  * Locate the display text in the window.
  793.  */
  794. void
  795. get_text_box(boxp, window)
  796. register Rect    *boxp;
  797. WindowPtr            window;
  798. {
  799.         *boxp = window->portRect;
  800.         boxp->right -= sBarWidth;
  801.         boxp->bottom -= sBarWidth;
  802.         InsetRect(boxp, TOP_MARGIN, SIDE_MARGIN);
  803. }
  804.